---
title: Internationalization
description: Learn how to use i18n routing in Astro.
i18nReady: false
---

import { FileTree } from '@astrojs/starlight/components';
import Since from '~/components/Since.astro'

Astro's internationalization (i18n) features allow you to adapt your project for an international audience.


## i18n Routing

<p><Since v="3.5.0" /></p>

Astro's i18n routing allows you to add your multilingual content with support for configuring a default language, computing relative page URLs, and accepting preferred languages provided by your visitor's browser. You can also specify fallback languages on a per-language basis so that your visitors can always be directed to existing content on your site.

This routing API helps you generate, use, and verify the URLs that your multi-language site produces. Check back and update regularly for the latest new features as this API continues to develop!


### Configure i18n routing

1. Enable the routing option by adding an `i18n` object to your Astro configuration with a [default location (`defaultLocale`) and a list of all languages to support (`locales`)](#defaultlocale-and-locales):

   ```js title="astro.config.mjs"
   import { defineConfig } from "astro/config"
   export default defineConfig({
     i18n: {
       defaultLocale: "en",
       locales: ["en", "es", "pt-br"]
     }
   })
   ```
  
2. Choose and configure a [`routing`](#routing) based on the desired URL path for your `defaultLocale`:

  - `"prefixDefaultLocale: false"` (default): URLs in your default language will **not** have a `/[locale]/` prefix. All other locales will.

  - `"prefixDefaultLocale: true"`: All URLs, including your default language, will have a `/[locale]/` prefix.

    ```js title="astro.config.mjs" ins={7}
    import { defineConfig } from "astro/config"
    export default defineConfig({
      i18n: {
        defaultLocale: "en",
        locales: ["es", "en", "fr"],
        routing: {
            prefixDefaultLocale: false
        }
      }
    })
    ```

3. Organize your content folders with localized content by language. Your folder names must match the items in `locales` exactly, and your folder organization must match the URL paths chosen for your [`routing`](#routing).

    Include a localized folder for your `defaultLocale` only if you configure `prefixDefaultLocale: true` to show a localized URL path.

    <FileTree>
    - src
      - pages
        - about.astro
        - index.astro
        - es
          - about.astro
          - index.astro
        - pt-br
          - about.astro
          - index.astro
    </FileTree>

    :::note
    The localized folders do not need to be at the root of the `/pages/` folder.
    
    Create individual `/[locale]/` folders anywhere within `src/pages/` and Astro's [file-based routing](/en/guides/routing/) will create your pages at corresponding URL paths. 
    :::
  
4. With i18n routing configured, you can now compute links to pages within your site using the [`getRelativeLocaleURL()`](#getrelativelocaleurl) helper available from the [`astro:i18n` module](#virtual-module-astroi18n). This will always provide the correct, localized route and can help you correctly use, or check, URLs on your site. You can also still write the links manually.

    ```astro title="src/pages/es/index.astro"
    ---
    import { getRelativeLocaleUrl } from 'astro:i18n';

    // defaultLocale is "es"
    const aboutURL=getRelativeLocaleUrl("es", "about");
    ---

    <a href="/get-started/">¡Vamos!</a>
    <a href={getRelativeLocaleUrl('es', 'blog')}>Blog</a>
    <a href={aboutURL}>Acerca</a> 
    ```

### `routing`

Astro's built-in file-based routing automatically creates URL routes for you based on your file structure within `src/pages/`. When you configure i18n routing, the `routing` value now allows you to specify your file structure (and corresponding URL paths generated) in order to use helper functions to generate, use, and verify the routes in your project.


#### `prefixDefaultLocale: false`

```js title="astro.config.mjs" ins={7}
import { defineConfig } from "astro/config"
export default defineConfig({
  i18n: {
    defaultLocale: "en",
    locales: ["es", "en", "fr"],
    routing: {
        prefixDefaultLocale: false
    }
  }
})
```

This is the **default** value. Set this option when URLs in your default language will **not** have a `/[locale]/` prefix and files in your default language exist at the root of `src/pages/`.

- `src/pages/blog.astro` will produce the route `example.com/blog/` 
- `src/pages/fr/blog.astro` will produce the route `example.com/fr/blog/` 
- If there is no file at `src/pages/es/blog.astro`, then the route `example.com/es/blog/` will 404 unless you specify a [fallback strategy](#fallback).


#### `prefixDefaultLocale: true`

```js title="astro.config.mjs" ins={7}
import { defineConfig } from "astro/config"
export default defineConfig({
  i18n: {
    defaultLocale: "en",
    locales: ["es", "en", "fr"],
    routing: {
        prefixDefaultLocale: true
    }
  }
})
```

Set this option when all routes will have their `/locale/` prefix in their URL and when all page content files, including those for your `defaultLocale`, exist in a localized folder:

    <FileTree>
    - src
      - pages
        - **index.astro** // Note: this file is always required
        - en
          - index.astro
          - about.astro
        - es
          - about.astro
          - index.astro
        - pt-br
          - about.astro
          - index.astro
    </FileTree>

- URLs without a locale prefix, (e.g. `example.com/blog/`) will return a 404 (not found) status code.

#### `redirectToDefaultLocale`

<p><Since v="4.2.0" /></p>

Configures whether or not the home URL (`/`) generated by `src/pages/index.astro` will redirect to `/<defaultLocale>`.

Setting `prefixDefaultLocale: true` will also automatically set `redirectToDefaultLocale: true` in your `routing` config object. By default, the required `src/pages/index.astro` file will automatically redirect to the index page of your default locale.

You can opt out of this behavior by [setting `redirectToDefaultLocale: false`](/en/reference/configuration-reference/#i18nroutingredirecttodefaultlocale). This allows you to have a site home page that exists outside of your configured locale folder structure.

#### `domains` (experimental)

<p><Since v="4.3.0" /></p>

This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured.

To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, set the `experimental.i18nDomains` flag to `true` and add `i18n.domains` to map any of your supported `locales` to custom URLs:

```js title="astro.config.mjs" {3-7} ins={14-21}
import { defineConfig } from "astro/config"
export default defineConfig({
  site: "https://example.com",
  output: "server", // required, with no prerendered pages
  adapter: node({
    mode: 'standalone',
  }),
  i18n: {
    defaultLocale: "en",
    locales: ["es", "en", "fr", "ja"],
    routing: {
      prefixDefaultLocale: false
    },
    domains: {
        fr: "https://fr.example.com",
        es: "https://example.es"
    }
  },
  experimental: {
    i18nDomains: true
  }
})
```
All non-mapped `locales` will follow your `prefixDefaultLocales` configuration. However, even if this value is `false`, page files for your `defaultLocale` must also exist within a localized folder. For the configuration above, an `/en/` folder is required.

With the above configuration: 

- The file `/fr/about.astro` will create the URL `https://fr.example.com/about`.
- The file `/es/about.astro` will create the URL `https://example.es/about`.
- The file `/ja/about/astro` will create the URL `https://example.com/ja/about`.
- The file `/en/about.astro` will create the URL `https://example.com/about`.

The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions.

##### Limitations

This feature has some restrictions:
- The `site` option is mandatory.
- The `output` option must be set to `"server"`.
- There cannot be any individual prerendered pages.
- The adapter feature [`functionPerRoute`](/en/reference/adapter-reference/#functionperroute) is not supported.

Astro relies on the following headers in order to support the feature:
- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host). Astro will use the former, and if not present, will try the latter.
- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`URL#protocol`](https://developer.mozilla.org/en-US/docs/Web/API/URL/protocol) of the server request.

Make sure that your server proxy/hosting platform is able to provide this information. Failing to retrieve these headers will result in a 404 (status code) page.

#### Routing logic

Astro uses a [middleware](/en/guides/middleware/) to implement its routing logic. This middleware function is placed in the [first position](/en/guides/middleware/#chaining-middleware) where it awaits every `Response` coming from any additional middleware and each page route before finally executing its own logic.

This means that operations (e.g. redirects) from your own middleware and your page logic are run first, your routes are rendered, and then the i18n middleware performs its own actions such as verifying that a localized URL corresponds to a valid route.

### `defaultLocale` and `locales`

Both a default language ([`defaultLocale`](/en/reference/configuration-reference/#i18ndefaultlocale)) and a list of all supported languages ([`locales`](/en/reference/configuration-reference/#i18nlocales)) must be specified in your `i18n` routing configuration.

Each entry in the `locales` configuration array must be either a string (e.g. `"fr"`, `"pt-br"`) or a [custom locale path](#custom-locale-paths). `locales` may contain a combination of strings and custom paths.

Your `/[locale]/` folder names must match exactly the `locale`s in the list (either the string or the `path` value), and your [routing](#routing) configuration must correspond to whether or not you have a localized folder for your default language. Every other supported language must have its own localized folder.

Depending on your deploy host, you may discover transformations in URL paths, so check your deployed site to determine the best syntax for your `locale` values.

### Custom locale paths

In addition to defining your site's supported `locales` as strings (e.g. "en", "pt-br"), Astro also allows you to map an arbitrary number of [browser-recognized language `codes`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax) to a custom URL `path`. While locales can be strings of any format as long as they correspond to your project folder structure, `codes` must follow the browser's accepted syntax.

Pass an object to the `locales` array with a `path` key to define a custom URL prefix, and `codes` to indicate the languages mapped to this URL. In this case, your `/[locale]/` folder name must match exactly the value of the `path` and your URLs will be generated using the `path` value.

This is useful if you support multiple variations of a language (e.g. `"fr"`, `"fr-BR"`, and `"fr-CA"`) and you want to have all these variations mapped under the same URL `/fr/`, or even customize it entirely (e.g. `/french/`):

```js title="astro.config.mjs" del={5} ins={6-9}
import { defineConfig } from "astro/config"
export default defineConfig({
  i18n: {
    defaultLocale: "en",
    locales: ["es", "en", "fr"],
    locales: ["es", "en", {
        path: "french", // no slashes included
        codes: ["fr", "fr-BR", "fr-CA"]
    }],
    routing: {
        prefixDefaultLocale: true
    }
  }
})
```

When using functions from the [`astro:i18n` virtual module](#virtual-module-astroi18n) to compute valid URL paths based on your configuration (e.g. `getRelativeLocaleUrl()`), [use the `path` as the value for `locale`](#generating-urls-from-custom-paths).

### Browser language detection

Astro’s i18n routing allows you to access two properties for browser language detection in pages rendered on demand: `Astro.preferredLocale` and `Astro.preferredLocaleList`. All pages, including static prerendered pages, have access to `Astro.currentLocale`.

These combine the browser's `Accept-Language` header, and your `locales` (strings or `codes`) to automatically respect your visitor's preferred languages.

- [`Astro.preferredLocale`](/en/reference/api-reference/#astropreferredlocale):  Astro can compute a **preferred locale** for your visitor if their browser's preferred locale is included in your `locales` array. This value is undefined if no such match exists.

- [`Astro.preferredLocaleList`](/en/reference/api-reference/#astropreferredlocalelist): An array of all locales that are both requested by the browser and supported by your website. This produces a list of all compatible languages between your site and your visitor. The value is `[]` if none of the browser's requested languages are found in your `locales` array. If the browser does not specify any preferred languages, then this value will be [`i18n.locales`].

- [`Astro.currentLocale`](/en/reference/api-reference/#astrocurrentlocale): The locale computed from the current URL, using the syntax specified in your `locales` configuration. If the URL does not contain a `/[locale]/` prefix, then the value will default to [`i18n.defaultLocale`](/en/reference/configuration-reference/#i18ndefaultlocale).

In order to successfully match your visitors' preferences, provide your `codes` using the same pattern [used by the browser](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax).

### Fallback

Astro's i18n routing allows you to configure a **fallback routing strategy**. When a page in one language doesn't exist (e.g. a page that is not yet translated), instead of displaying a 404 page, you can redirect a user from one locale to another on a per-language basis. This is useful when you do not yet have a page for every route, but you want to still provide some content to your visitors.

For example, the configuration below sets `es` as the fallback locale for any missing `fr` routes. This means that a user visiting `example.com/fr/my-page/` will be redirected to and shown the content for `example.com/es/my-page/` instead of being taken to a 404 page when `src/pages/fr/my-page.astro` does not exist.

```js title="astro.config.mjs" ins={6-8} 
import { defineConfig } from "astro/config"
export default defineConfig({
  i18n: {
    defaultLocale: "en",
    locales: ["es", "en", "fr"],
    fallback: {
      fr: "es"  
    }
  }
})
```

Astro will ensure that a page is built in `src/pages/fr` for every page that exists in `src/pages/es/`. If the page does not already exist, then a page with a redirect to the corresponding `es` route will be created.

## Virtual module `astro:i18n`

This module provides functions that can help you create URLs using your project's configured locales.

Creating routes for your project with the i18n router will depend on certain configuration values you have set that affect your page routes. When creating routes with these functions, be sure to take into account your individual settings for:

- [`base`](/en/reference/configuration-reference/#base)
- [`trailingSlash`](/en/reference/configuration-reference/#trailingslash)
- [`build.format`](/en/reference/configuration-reference/#buildformat)
- [`site`](/en/reference/configuration-reference/#site)

Also, note that the returned URLs created by these functions for your `defaultLocale` will reflect your `i18n.routing` configuration.

URLs created when `prefixDefaultLocale: true` is configured will include a `/lang/` path in the URL. URLs created with `prefixDefaultLocale: false` will not include a language prefix.

### `getRelativeLocaleUrl()`

`getRelativeLocaleUrl(locale: string, path: string, options?: GetLocaleOptions): string`

Use this function to retrieve a relative path for a locale. If the locale doesn't exist, Astro throws an error. 

```astro
---
getRelativeLocaleUrl("fr");
// returns /fr

getRelativeLocaleUrl("fr", "");
// returns /fr

getRelativeLocaleUrl("fr", "getting-started");
// returns /fr/getting-started

getRelativeLocaleUrl("fr_CA", "getting-started", {
  prependWith: "blog"
}); 
// returns /blog/fr-ca/getting-started

getRelativeLocaleUrl("fr_CA", "getting-started", {
  prependWith: "blog",
  normalizeLocale: false
}); 
// returns /blog/fr_CA/getting-started
---
```

### `getAbsoluteLocaleUrl()` 

`getAbsoluteLocaleUrl(locale: string, path: string, options?: GetLocaleOptions): string`


Use this function to retrieve an absolute path for a locale when [`site`] has a value. If [`site`] isn't configured, the function returns a relative URL. If the locale doesn't exist, Astro throws an error.


```astro title="src/pages/index.astro"
---
// If `site` is set to be `https://example.com`

getAbsoluteLocaleUrl("fr"); 
// returns https://example.com/fr

getAbsoluteLocaleUrl("fr", ""); 
// returns https://example.com/fr

getAbsoluteLocaleUrl("fr", "getting-started"); 
// returns https://example.com/fr/getting-started

getAbsoluteLocaleUrl("fr_CA", "getting-started", {
  prependWith: "blog"
}); 
// returns https://example.com/blog/fr-ca/getting-started

getAbsoluteLocaleUrl("fr_CA", "getting-started", {
  prependWith: "blog",
  normalizeLocale: false
}); 
// returns https://example.com/blog/fr_CA/getting-started
---
```

### `getRelativeLocaleUrlList()`

Use this like [`getRelativeLocaleUrl`](#getrelativelocaleurl) to return a list of relative paths for all the locales.


`getRelativeLocaleUrlList(path?: string, options?: GetLocaleOptions): string[]`

### `getAbsoluteLocaleUrlList()`

`getAbsoluteLocaleUrlList(path?: string, options?: GetLocaleOptions): string[]`

Use this like [`getAbsoluteLocaleUrl`](#getabsolutelocaleurl) to return a list of absolute paths for all the locales.

### `getPathByLocale(locale: string): string`

A function that returns the `path` associated to one or more `codes` when [custom locale paths](#custom-locale-paths) are configured.

### Generating URLs from custom paths

When a `locale` is a custom path, use the `path` as the value for `locale`.

For example, use `french` in the i18n helper functions for the `locales` configuration below:

```js
locales: ["es", "en", {
  path: "french",
  codes: ["fr", "fr-BR", "fr-CA"]
}],
```

```astro title="src/pages/index.astro"
---
import { getPathByLocale, getRelativeLocaleUrl, getLocaleByPath } from "astro:i18n";

getRelativeLocaleUrl("french", "blog"); // returns /french/blog
---
```
Note that other `astro:i18n` functions will return the following results for the same configuration:
 
```astro title="src/pages/index.astro"
---
getPathByLocale("fr"); // returns "french"
getPathByLocale("fr-CA"); // returns "french"
getLocaleByPath("french"); // returns "fr" because that's the first code configured
---
```

### `getLocaleByPath(path: string): string`

A function that returns the `code` associated to a locale `path`.

### Retrieve the locale for a custom path

Given a custom path configured with multiple `codes`, the function will return the **first** code configured:

```js
// astro.config.mjs
import {defineConfig} from "astro/config"
export default defineConfig({
    i18n: {
        defaultLocale: "en",
        locales: ["en", "es", "fr", {
            path: "portugues",
            codes: ["pt-AO", "pt", "pt-BR"]
        }]
    }
})
```

```astro
---
// src/pages/index.astro
import { getLocaleByPath } from "astro:i18n";
console.log(getLocaleByPath("en")) // will log "en"
console.log(getLocaleByPath("fr")) // will log "fr"
console.log(getLocaleByPath("portugues")) // will log "pt-AO"
---
```

[`site`]: /en/reference/configuration-reference/#site
[`i18n.locales`]: /en/reference/configuration-reference/#i18nlocales
